package com.zzyl.nursing.service.impl;

import java.lang.reflect.ParameterizedType;
import java.util.*;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.IdcardUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.xiaoymin.knife4j.core.util.CommonUtils;
import com.zzyl.common.exception.base.BaseException;
import com.zzyl.common.utils.DateUtils;
import com.zzyl.common.utils.UserThreadLocal;
import com.zzyl.framework.web.service.TokenService;
import com.zzyl.nursing.domain.*;
import com.zzyl.nursing.dto.AddFamilyDto;
import com.zzyl.nursing.dto.UserLoginRequestDto;
import com.zzyl.nursing.mapper.*;
import com.zzyl.nursing.service.IDeviceService;
import com.zzyl.nursing.service.WechatService;

import com.zzyl.nursing.vo.FamilyMemberElderVo;
import com.zzyl.nursing.vo.ListByPageVo;
import com.zzyl.nursing.vo.LoginVo;
import com.zzyl.nursing.vo.PropertyStatusInfoVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.zzyl.nursing.service.IFamilyMemberService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import static com.zzyl.common.utils.SecurityUtils.getLoginUser;

/**
 * 老人家属Service业务层处理
 *
 * @author alexis
 * @date 2025-01-09
 */
@Service
public class FamilyMemberServiceImpl extends ServiceImpl<FamilyMemberMapper, FamilyMember> implements IFamilyMemberService {
    @Autowired
    private FamilyMemberMapper familyMemberMapper;
    @Autowired
    private WechatService wechatService;
    @Autowired
    private TokenService tokenService;
    @Autowired
    private ElderMapper elderMapper;
    @Autowired
    private DeviceMapper deviceMapper;
    @Autowired
    private ContractMapper contractMapper;
    @Autowired
    private DeviceDataMapper deviceDataMapper;

    @Autowired
    private AlertRuleMapper alertRuleMapper;
    @Autowired
    private IDeviceService deviceService;
    @Autowired
    private FamilyMemberElderMapper familyMemberElderMapper;
    static List<String> DEFAULT_NICKNAME_PREFIX = ListUtil.of(
            "生活更美好",
            "大桔大利",
            "日富一日",
            "好柿开花",
            "柿柿如意",
            "一椰暴富",
            "大柚所为",
            "杨梅吐气",
            "天生荔枝"
    );
    @Autowired
    private RoomTypeMapper roomTypeMapper;
    @Autowired
    private BedMapper bedMapper;
    private AlertDataMapper alertDataMapper;

    /**
     * 查询老人家属
     *
     * @param id 老人家属主键
     * @return 老人家属
     */
    @Override
    public FamilyMember selectFamilyMemberById(Long id) {
        return familyMemberMapper.selectById(id);
    }

    /**
     * 查询老人家属列表
     *
     * @param familyMember 老人家属
     * @return 老人家属
     */
    @Override
    public List<FamilyMember> selectFamilyMemberList(FamilyMember familyMember) {
        return familyMemberMapper.selectFamilyMemberList(familyMember);
    }

    /**
     * 新增老人家属
     *
     * @param familyMember 老人家属
     * @return 结果
     */
    @Override
    public int insertFamilyMember(FamilyMember familyMember) {
        return familyMemberMapper.insert(familyMember);
    }

    /**
     * 修改老人家属
     *
     * @param familyMember 老人家属
     * @return 结果
     */
    @Override
    public int updateFamilyMember(FamilyMember familyMember) {
        return familyMemberMapper.updateById(familyMember);
    }

    /**
     * 批量删除老人家属
     *
     * @param ids 需要删除的老人家属主键
     * @return 结果
     */
    @Override
    public int deleteFamilyMemberByIds(Long[] ids) {
        return familyMemberMapper.deleteBatchIds(Arrays.asList(ids));
    }

    /**
     * 删除老人家属信息
     *
     * @param id 老人家属主键
     * @return 结果
     */
    @Override
    public int deleteFamilyMemberById(Long id) {
        return familyMemberMapper.deleteById(id);
    }

    /**
     * 小程序登录
     *
     * @param userLoginRequestDto 请求参数
     * @return 返回token和nickName
     */
    @Override
    public LoginVo login(UserLoginRequestDto userLoginRequestDto) {
        //调用微信官方接口获取openId
        String openId = wechatService.getOpenId(userLoginRequestDto.getCode());

        //根据openId从数据库中查询数据
        FamilyMember familyMember = getOne(Wrappers.<FamilyMember>lambdaQuery().eq(FamilyMember::getOpenId, openId));

        //如果用户不存在  创建一个用户  并绑定openId
        if (ObjectUtil.isEmpty(familyMember)) {
            //创建新用户
            familyMember = new FamilyMember();
            familyMember.setOpenId(openId);
        }

        //根据detailcode 获取手机号
        String phone = wechatService.getPhone(userLoginRequestDto.getPhoneCode());
        familyMember.setPhone(phone);
        //新增或更新用户
        updateOrInsert(familyMember);

        //封装用户信息到token  返回小程序
        //调用方法生成token
        Map<String, Object> claim = new HashMap<>();
        claim.put("userId", familyMember.getId());
        claim.put("nickName", familyMember.getName());
        String token = tokenService.createToken(claim);
        LoginVo loginVo = new LoginVo();
        loginVo.setToken(token);
        loginVo.setNickName(familyMember.getName());
        //返回LoginVo
        return loginVo;
    }

    private void updateOrInsert(FamilyMember familyMember) {
        //判断id是否为空来决定是新增还是更新
        if (ObjectUtil.isEmpty(familyMember.getId())) {
            //新增

            //姓名格式为随机姓名加手机号后四位
            familyMember.setName(DEFAULT_NICKNAME_PREFIX.get((int) (Math.random() * DEFAULT_NICKNAME_PREFIX.size())) + familyMember.getPhone().substring(7));
            familyMemberMapper.insert(familyMember);
        } else {
            updateById(familyMember);
        }
    }

    /**
     * 添加家属
     *
     * @param familyDto
     */
    @Override
    public Integer addFamily(AddFamilyDto familyDto) {
        Long userId = UserThreadLocal.getUserId();
        //判断是否登录
        if (ObjectUtil.isEmpty(userId)) {
            throw new BaseException("请先登录");
        }
        //判断身份证号是否正确 判断身份证是否为空 判断姓名是否为空
        if (ObjectUtil.isEmpty(familyDto.getIdCard()) || ObjectUtil.isEmpty(familyDto.getName()) || !IdcardUtil.isValidCard(familyDto.getIdCard())) {
            throw new BaseException("身份证号格式有误或暂无老人信息");
        }


        //查询养老院中是否存在老人
        Elder elder = elderMapper.selectOne(Wrappers.<Elder>lambdaQuery()
                .eq(Elder::getIdCardNo, familyDto.getIdCard())
                .eq(Elder::getName, familyDto.getName()));
        if (ObjectUtil.isEmpty(elder)) {
            throw new BaseException("该老人未入住");
        }
        //查询该老人是否签订合同
        Contract contract = contractMapper.selectOne(Wrappers.<Contract>lambdaQuery()
                .eq(Contract::getElderId, elder.getId()));
        //判断是否有合同 如果没有签订  则提示该老人未签订合同
        if (ObjectUtil.isEmpty(contract)) {
            throw new BaseException("该老人未签订合同");
        }
        //根据老人id判断是否重复添加了家属
        Long elderId = elder.getId();
        Long count = familyMemberElderMapper.selectCount(Wrappers.<FamilyMemberElder>lambdaQuery()
                .eq(FamilyMemberElder::getElderId, elderId));
        if (count != 0) {
            throw new BaseException("该老人已添加家属,请勿重复添加");
        }


        FamilyMemberElder familyMemberElder = new FamilyMemberElder();
        familyMemberElder.setElderId(elder.getId());
        familyMemberElder.setFamilyMemberId(userId);
        familyMemberElder.setRemark(familyDto.getRemark());
        familyMemberElder.setCreateBy(String.valueOf(userId));
        familyMemberElder.setUpdateBy(String.valueOf(userId));
        int i = familyMemberElderMapper.insert(familyMemberElder);
        return i;
    }

    /**
     * 获取我的家属
     *
     * @return
     */
    @Override
    public List<FamilyMemberElderVo> getMyFamily() {


//查询出是该登录人所绑定的家属列表
        List<FamilyMemberElder> familyMemberElders = familyMemberElderMapper.selectList(Wrappers.<FamilyMemberElder>lambdaQuery()
                .eq(FamilyMemberElder::getFamilyMemberId, UserThreadLocal.getUserId()));
        FamilyMemberElderVo familyMemberElderVo = new FamilyMemberElderVo();
        List<FamilyMemberElderVo> familyMemberElderVos = new ArrayList<>();
        familyMemberElders.forEach(familyMemberElder -> {
            BeanUtils.copyProperties(familyMemberElder, familyMemberElderVo);
            familyMemberElderVo.setElderName(elderMapper.selectById(familyMemberElder.getElderId()).getName());

            familyMemberElderVos.add(familyMemberElderVo);
        });
        return familyMemberElderVos;
    }

    /**
     * 查看已绑定家人列表（分页查询)
     *
     * @param pageNum
     * @param pageSize
     * @return
     */
    @Override
    public List<ListByPageVo> listByPage(Integer pageNum, Integer pageSize) {

        List<ListByPageVo> list = new ArrayList<>();

        //获取绑定家属列表
        List<FamilyMemberElder> familyMemberElders = familyMemberElderMapper.selectList(Wrappers.<FamilyMemberElder>lambdaQuery()
                .eq(FamilyMemberElder::getFamilyMemberId, UserThreadLocal.getUserId()));
        familyMemberElders.forEach(familyMemberElder -> {
            //todo
            ListByPageVo listByPageVo = new ListByPageVo();
            //获取老人列表
            List<Elder> elders = elderMapper.selectList(Wrappers.<Elder>lambdaQuery()
                    .eq(Elder::getId, familyMemberElder.getElderId()));
            elders.forEach(elder -> {
                listByPageVo.setName(elder.getName());
                listByPageVo.setImage(elder.getImage());
                listByPageVo.setBedNumber(elder.getBedNumber());
                //调用方法 根据床位编号查询房间类型名称
                String typeName = selectRoomTypeByBedNumber(elder.getBedNumber());
                listByPageVo.setTypeName(typeName);
                //调用方法查询房间id
                String roomId = selectRoomIdByBedNumber(elder.getBedNumber());
                //调用方法获取烟雾报警 睡眠监测带设备信息并进行封装
                getDevice(roomId, elder, listByPageVo);
               /* Device device1 = deviceMapper.selectOne(Wrappers.<Device>lambdaQuery().eq(Device::getBindingLocation, roomId));
                if(ObjectUtil.isNotEmpty(device1)){
                    listByPageVo.setIotId(device1.getIotId());
                    listByPageVo.setDeviceName(device1.getDeviceName());
                    listByPageVo.setProductKey(device1.getProductKey());
                }

                //获取睡眠监测带设备
                Device device3 = deviceMapper.selectOne(Wrappers.<Device>lambdaQuery().eq(Device::getBindingLocation, elder.getBedId()));
                if(ObjectUtil.isNotEmpty(device3)){
                    listByPageVo.setIotId(device3.getIotId());
                    listByPageVo.setDeviceName(device3.getDeviceName());
                    listByPageVo.setProductKey(device3.getProductKey());
                }*/
                //获取智能手表设备
                Device device2 = deviceMapper.selectOne(Wrappers.<Device>lambdaQuery().eq(Device::getBindingLocation, elder.getId()));
                if (ObjectUtil.isNotEmpty(device2)) {
                    listByPageVo.setIotId(device2.getIotId());
                    listByPageVo.setDeviceName(device2.getDeviceName());
                    listByPageVo.setProductKey(device2.getProductKey());
                }

            });

            listByPageVo.setMid(String.valueOf(familyMemberElder.getId()));
            listByPageVo.setMremark(familyMemberElder.getRemark());
            listByPageVo.setElderId(String.valueOf(familyMemberElder.getElderId()));
            list.add(listByPageVo);
        });


        return list;
    }

    /**
     * 根据房间id 老人床位或房间号或者查询三种设备信息 并进行封装
     *
     * @param roomId
     * @param elder
     */
    private void getDevice(String roomId, Elder elder, ListByPageVo listByPageVo) {
        Device device = deviceMapper.selectOne(Wrappers.<Device>lambdaQuery().eq(Device::getBindingLocation, elder.getBedId()));

        if (ObjectUtil.isNotEmpty(device)) {
            listByPageVo.setIotId(device.getIotId());
            listByPageVo.setDeviceName(device.getDeviceName());
            listByPageVo.setProductKey(device.getProductKey());
        }
    }


    /**
     * 根据床位编号查询该床位所属房间id
     *
     * @param bedNumber
     * @return
     */
    private String selectRoomIdByBedNumber(String bedNumber) {
        String roomId = bedMapper.selectRoomIdByBedNumber(bedNumber);
        return roomId;
    }

    /**
     * 根据床位编号查询该床位所属房间类型名称
     *
     * @param bedNumber
     * @return
     */
    private String selectRoomTypeByBedNumber(String bedNumber) {
        String typeName = bedMapper.selectRoomTypeByBedNumber(bedNumber);
        return typeName;
    }

    /**
     * 1.4 查询健康数据
     *
     * @param deviceName
     * @param productKey
     * @return
     */
    @Override
    public List<PropertyStatusInfoVo> queryDevicePropertyStatus(String deviceName, String productKey) {
        /*Device device = deviceMapper.selectOne(Wrappers.<Device>lambdaQuery().eq(ObjectUtil.isNotEmpty(deviceName), Device::getDeviceName, deviceName)
                .eq(ObjectUtil.isNotEmpty(productKey), Device::getProductKey, productKey));*/
        List<PropertyStatusInfoVo> list = new ArrayList<>();

        DeviceData deviceData = deviceDataMapper.selectOne(Wrappers.<DeviceData>lambdaQuery().eq(ObjectUtil.isNotEmpty(deviceName), DeviceData::getDeviceName, deviceName)
                .eq(ObjectUtil.isNotEmpty(productKey), DeviceData::getProductKey, productKey));
        if (ObjectUtil.isEmpty(deviceData)){
            throw   new BaseException("该设备没有数据");
        }

        PropertyStatusInfoVo propertyStatusInfoVo = new PropertyStatusInfoVo();
        String[] split = ObjectUtil.toString(deviceData.getDataValue()).split(",");
        String[] split1 = split[1].split(":");
        String[] split2 = split[0].split(":");

        //获得split1[1]的数据类型
        //todo

        propertyStatusInfoVo.setDataType(Objects.toString(split1[0]));

        propertyStatusInfoVo.setDataType(split1[0]);

        //通过报警规则查询获得功能名称 持续周期  并进行封装
        AlertRule alertRule = alertRuleMapper.selectOne(Wrappers.<AlertRule>lambdaQuery().eq(AlertRule::getDeviceName, deviceName)
                .eq(AlertRule::getProductKey, productKey));
        propertyStatusInfoVo.setName(alertRule.getFunctionName());
        propertyStatusInfoVo.setUnit(alertRule.getAlertEffectivePeriod());
        propertyStatusInfoVo.setValue(split1[1]);
        propertyStatusInfoVo.setTime(split2[1]);
        propertyStatusInfoVo.setIdentifier(deviceData.getFunctionId());
        list.add(propertyStatusInfoVo);
        return list;
    }
}
